﻿#include "VTKOCCT.h"
#include <BRepPrimAPI_MakeBox.hxx>
#include <BRepPrimAPI_MakeCone.hxx>
#include <IVtkTools_ShapeDataSource.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <vtkAutoInit.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkPolyDataMapper.h>
#include <IGESControl_Reader.hxx> 
#include <STEPCAFControl_Reader.hxx>
//Lesson 17
#include <Bnd_Box.hxx>
#include <BRepBndLib.hxx>
#include <BRepBuilderAPI_MakeVertex.hxx>
#include <vtkCubeSource.h>
#include <vtkEllipseArcSource.h>
#include <vtkSphereSource.h>
#include <vtkConeSource.h>
#include <vtkAppendPolyData.h >
#include <vtkCleanPolyData.h >
#include <vtkNew.h>
#include <vtkPoints.h>
#include <vtkCellArray.h>
#include <vtkBoundingBox.h>
#include <vtkAxesActor.h>


decltype(auto) ReadIges(const char* file) {
	IGESControl_Reader reader;
	reader.ReadFile(file);
	reader.TransferRoots();
	TopoDS_Shape shape = reader.OneShape();
	vtkNew<vtkPolyData> polydata;
	vtkNew<vtkPolyDataMapper> mapper;
	vtkNew<vtkActor> actor;
	vtkNew<IVtkTools_ShapeDataSource> shapeSource;
	shapeSource->SetShape(new IVtkOCC_Shape(shape));
	shapeSource->Update();
	mapper->SetInputConnection(shapeSource->GetOutputPort());
	actor->SetMapper(mapper);
	return actor;
}

decltype(auto) ReadStep(const char* file) {
	STEPControl_Reader readerSTEP;
	IFSelect_ReturnStatus statSTEP = readerSTEP.ReadFile(file);
	IFSelect_PrintCount modeSTEP = IFSelect_ListByItem;
	readerSTEP.PrintCheckLoad(Standard_False, modeSTEP);
	readerSTEP.TransferRoots();
	TopoDS_Shape shape = readerSTEP.OneShape();
	
	vtkNew<vtkPolyDataMapper> mapper;
	vtkNew<vtkActor> actor;
	vtkNew<IVtkTools_ShapeDataSource> shapeSource;
	
	shapeSource->SetShape(new IVtkOCC_Shape(shape));
	shapeSource->Update();
	mapper->SetInputConnection(shapeSource->GetOutputPort());
	actor->SetMapper(mapper);
	return actor;
}

decltype(auto) TopoDSShapeSphere() {
	//TopoDS_ShapeSphere
	gp_Ax2 sphere_origin(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1));
	BRepPrimAPI_MakeCone mkCone(sphere_origin, 1.0, 0.01, 1);
	const TopoDS_Shape& TopoDS_ShapemkConeTMP = mkCone.Shape();
	TopoDS_Shape TopoDS_ShapeCONE = static_cast<TopoDS_Shape>(TopoDS_ShapemkConeTMP);
	gp_Trsf TSPHERE;
	TSPHERE.SetScaleFactor(0.9);
	TSPHERE.SetTranslationPart(gp_Vec(0, 0, 0));
	BRepBuilderAPI_Transform stepBRepTransformationTOPBOX(TopoDS_ShapeCONE, TSPHERE, Standard_True);
	TopoDS_ShapeCONE = stepBRepTransformationTOPBOX.Shape();

	vtkNew<IVtkTools_ShapeDataSource> TOPOCONESource;
	TOPOCONESource->SetShape(new IVtkOCC_Shape(TopoDS_ShapeCONE));

	vtkNew<vtkActor> actorTOPOCONE;
	vtkNew<vtkPolyDataMapper> mapperTOPOCONE;
	actorTOPOCONE->SetMapper(mapperTOPOCONE);
	mapperTOPOCONE->SetInputConnection(TOPOCONESource->GetOutputPort());
	return actorTOPOCONE;
}

decltype(auto) VTKpointOnMeshes(const char* file) {
	STEPControl_Reader readerSTEP;
	IFSelect_ReturnStatus statSTEP = readerSTEP.ReadFile(file);
	IFSelect_PrintCount modeSTEP = IFSelect_ListByItem;
	readerSTEP.PrintCheckLoad(Standard_False, modeSTEP);
	readerSTEP.TransferRoots();
	TopoDS_Shape TopoDS_ShapeSTEP = readerSTEP.OneShape();


	//VTKpointOnMeshes
	vtkNew<vtkPoints> VTKpointsOnMeshes;
	vtkNew<vtkCellArray> verticesForVTKpointsOnMeshes;
	vtkIdType pid[1];

	//vtkPolyData creation
	vtkNew<vtkPolyData> PolyDataVTKPointsOnMeshes;

	//vtkPolyData initialization
	PolyDataVTKPointsOnMeshes->SetPoints(VTKpointsOnMeshes);
	PolyDataVTKPointsOnMeshes->SetVerts(verticesForVTKpointsOnMeshes);

	//VTKpoint IGES, STEP TopoDS_ShapeBOX CALC   
	Bnd_Box aabb;
	//AABB ALGO Per TopoDS_Shape mesh  , Please choose the source you like to run and put it in next line
	BRepBndLib::Add(TopoDS_ShapeSTEP, aabb, true); //TopoDS_ShapeIGES  //TopoDS_ShapeSTEP //TopoDS_ShapeCONE
	//VTKpointIGES CALC per TopoDS_Shape mesh
	int density = 20;
	gp_XYZ Pmin = aabb.CornerMin().XYZ();
	gp_XYZ Pmax = aabb.CornerMax().XYZ();
	gp_XYZ D = Pmax - Pmin;
	double dim[3] = { D.X(),D.Y(),D.Z() };
	double mind = Min(dim[0], Min(dim[1], dim[2]));
	const double d = mind / density;
	int nslice[3] = {
		int(Round(dim[0] / d)) + 1 ,
		int(Round(dim[1] / d)) + 1 ,
		int(Round(dim[2] / d)) + 1 };
	for (int i = 0; i < nslice[0]; ++i)
		for (int j = 0; j < nslice[1]; ++j)
			for (int k = 0; k < nslice[2]; ++k)
			{
				gp_XYZ p = Pmin
					+ gp_XYZ(d * i, 0, 0)
					+ gp_XYZ(0, d * j, 0)
					+ gp_XYZ(0, 0, d * k);
				pid[0] = VTKpointsOnMeshes->InsertNextPoint(p.X(), p.Y(), p.Z());
				verticesForVTKpointsOnMeshes->InsertNextCell(1, pid);
			};

	//Append the meshes
	vtkNew<vtkAppendPolyData> appendFilter;
	appendFilter->AddInputData(PolyDataVTKPointsOnMeshes);

	//Remove any duplicate points.
	vtkNew<vtkCleanPolyData> cleanFilterForMapperVTKShapes;
	cleanFilterForMapperVTKShapes->SetInputConnection(appendFilter->GetOutputPort());
	cleanFilterForMapperVTKShapes->Update();

	vtkNew<vtkPolyDataMapper> mapperVTKShapes;
	mapperVTKShapes->SetInputConnection(cleanFilterForMapperVTKShapes->GetOutputPort());

	vtkNew<vtkActor> actorVTKShapes;
	actorVTKShapes->SetMapper(mapperVTKShapes);
	return actorVTKShapes;
}

VTKOCCT::VTKOCCT(QWidget* parent)
	: QMainWindow(parent)
{
	vtkWidget = new QVTKOpenGLNativeWidget(this);
	this->resize(600, 400);
	this->setCentralWidget(vtkWidget);

	// ViewPort分割
	double xmins[4] = { 0, 0.5, 0 ,0.5 };
	double xmaxs[4] = { 0.5, 1, 0.5,1 };
	double ymins[4] = { 0, 0, 0.5,0.5 };
	double ymaxs[4] = { 0.5, 0.5, 1,1 };

	auto igesActor = ReadIges("D:/TEST/3D/igs/激光剑 .igs");
	auto rendererIges = vtkSmartPointer< vtkRenderer >::New();
	rendererIges->SetViewport(xmins[0], ymins[0], xmaxs[0], ymaxs[0]);
	rendererIges->AddActor(igesActor);

	auto stepActor = ReadStep("D:/TEST/3D/step/Assem1.STEP");
	auto rendererStep = vtkSmartPointer< vtkRenderer >::New();
	rendererStep->SetViewport(xmins[1], ymins[1], xmaxs[1], ymaxs[1]);
	rendererStep->AddActor(stepActor);

	auto topoActor = TopoDSShapeSphere();
	auto rendererTopo = vtkSmartPointer< vtkRenderer >::New();
	rendererTopo->SetViewport(xmins[2], ymins[2], xmaxs[2], ymaxs[2]);
	rendererTopo->AddActor(topoActor);

	auto vTKpointOnMeshes = VTKpointOnMeshes("D:/TEST/3D/step/叶片.STEP");
	auto rendererVTKpointOnMeshes = vtkSmartPointer< vtkRenderer >::New();
	rendererVTKpointOnMeshes->SetViewport(xmins[3], ymins[3], xmaxs[3], ymaxs[3]);
	rendererVTKpointOnMeshes->AddActor(vTKpointOnMeshes);
	vtkNew<vtkAxesActor> axes;
	// 总长
	// 初始化数组
	double axesLength[3]{ 100,100,100 };
	axes->SetTotalLength(axesLength);
	rendererIges->AddActor(axes);
	vtkWidget->renderWindow()->AddRenderer(rendererIges);
	vtkWidget->renderWindow()->AddRenderer(rendererStep);
	vtkWidget->renderWindow()->AddRenderer(rendererTopo);
	vtkWidget->renderWindow()->AddRenderer(rendererVTKpointOnMeshes);
}

VTKOCCT::~VTKOCCT()
{
	vtkWidget->interactor()->SetRenderWindow(nullptr);
	vtkWidget->interactor()->SetInteractorStyle(nullptr);
}
